package com.mi.soul.whale.common.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.mi.rule.util.EnvKit;
import com.mi.rule.util.StrKit;
import com.mi.rule.util.project.MiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 凭证签发工具
 *
 * @author 王永吉
 */
@Slf4j
@Component
public class JwtKit {
    //    签名算法
    private static Algorithm algorithm256 = null;
    //    签名验证工具
    private static JWTVerifier jwtVerifier = null;

    //    生成Token
    public static String createToken(Map<String, Object> parameter) {
        return createToken(parameter, null);
    }

    //    生成Token
    public static String createToken(Object time) {
        return createToken(null, time);
    }

    /**
     * 生成Token
     *
     * @param parameter 携带参数，getParam方法读取参数
     * @param time      失效时间
     * @return 生成签名字符串
     */
    public static String createToken(Map<String, Object> parameter, Object time) {
        //默认两小时
        if (time == null) {
            time = 2 * 60 * 60 * 1000;
        }
        Date withExpiresAt = new Date(new Date().getTime() + Long.parseLong(time.toString()));
        if (parameter == null) {
            parameter = new HashMap<>(1);
        }
        return JWT.create()
                .withClaim("parameter", JSON.toJSONString(parameter))//可读取的参数信息（别存太多）
                .withExpiresAt(withExpiresAt)//超时时间
                .sign(getAlgorithm256()); //signature
    }

    //检查失效
    public static boolean check(Object token) {
        if (StrKit.isBlank(token)) return false;
        try {
            getJwtVerifier().verify(token.toString());
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取整个参数对象
     */
    public static JSONObject getParam(String token) {
        return JSON.parseObject(claims(token).get("parameter").asString());
    }

    /**
     * 获取指定 Key 的 Value
     */
    public static String getParam(String token, String key) {
        return JSON.parseObject(claims(token).get("parameter").asString()).getString("key");
    }

    //获取用户ID
    public static String userId(String token) {
        return getParam(token, "userId");
    }

    //创建时间
    public static String createTime(String token) {
        return getParam(token, "createTime");
    }

    //获取用户ID
    public static String roleId(String token) {
        return getParam(token, "roleId");
    }

    //获取用户登录IP
    public static String loginIp(String token) {
        return getParam(token, "loginIp");
    }

    //获取Claims
    private static Map<String, Claim> claims(String token) {
        try {
            return getJwtVerifier().verify(token).getClaims();
        } catch (MiException e) {
            throw new MiException(ResMsg.ERROR_401);
        }
    }

    //秘钥
    private static String secret() {
        String miAuthSecret = EnvKit.getProperty("mi.auth.secret");
        if (StrKit.isBlank(miAuthSecret)) {
            throw new MiException(ResMsg.ERROR_MISSING_SECRET);
        }
        return miAuthSecret;
    }

    private static Algorithm getAlgorithm256() {
        if (algorithm256 == null) {
            initAlgorithm();
        }
        return algorithm256;
    }

    private static JWTVerifier getJwtVerifier() {
        if (jwtVerifier == null) {
            initJwtVerifier();
        }
        return jwtVerifier;
    }

    /**
     * 双重锁检查
     */
    private synchronized static void initAlgorithm() {
        if (algorithm256 == null) {
            algorithm256 = Algorithm.HMAC256(secret());
        }
    }

    /**
     * 双重锁检查
     */
    private synchronized static void initJwtVerifier() {
        if (jwtVerifier == null) {
            jwtVerifier = JWT.require(getAlgorithm256()).build();
        }
    }
}